//{===========================================================
//! @file Disassembler.c
//============================================================}
#include <stdio.h>
#include <assert.h>
#include "Commands.h"

int main()
{
    FILE* in_code = fopen("Out_code.txt", "r");
    FILE* out_text = fopen("Outtext.txt", "w");
    disassembler( in_code, out_text);
    fclose( in_code);
    fclose( out_text);
    return 0;
}

#define CMD_CHECK(cmd,name) if(CMD_##name == cmd) fprintf(out_file, #name); else

int disassembler(FILE* in_code, FILE* out_file)
{
    assert( in_code);
    assert( out_file);
    double new_code[MAX_SIZE_OF_CODE] = {0};
    char ok_sign[2];
    fscanf(in_code, "%s", ok_sign);
    SIGN[2] = '\0';
    if (strcmp( SIGN, ok_sign))
    {
        printf("It seems the file has wrong signature!\nYours one is '%s', but it should be '%s'\nSorry, program is aborting...\n ", ok_sign, SIGN);
        assert( 0 );
    }
    else printf("The signature is correct! Thanks!\n");
    fprintf(out_file, "%s\n", SIGN);
    int        neof = 1,
             length = 0,
           now_cmnd = 0;
    while (neof)
    {
        fscanf( in_code, "%d", &now_cmnd);
        assert( 0 <= length < MAX_SIZE_OF_CODE);
        new_code[length] = now_cmnd;
        if ( now_cmnd == CMD_EF)
        neof = 0;
        length++;
    }
    int    position = 0,
                  i = 0,
        numb_of_cmd = 0;
    int      label_for_str[MAX_SIZE_OF_CODE] = {0};
    int     str_togo_using_label[MAX_LABELS] = {0};
    int  label_used_in_str[MAX_SIZE_OF_CODE] = {0};
    for ( i = 0; i < MAX_LABELS; i++)
        str_togo_using_label[i] = -1;

    int      numb_of_labels =  0,
          str_for_label_now =  0;

    neof = 1;
    length = 0;
    while (  new_code[position] != CMD_EF)
    {

        assert( 0 <= position < MAX_SIZE_OF_CODE);
        numb_of_cmd = new_code[position];
        if (
            #include "JMP.h"
            )
        {
            assert( 0 <= position + 1 < MAX_SIZE_OF_CODE);
            str_for_label_now = new_code[++position];
            assert( 0 <= str_for_label_now < MAX_SIZE_OF_CODE);
            if ( label_for_str[str_for_label_now] == 0)
                {
                    numb_of_labels++;
                    assert( 0 <= numb_of_labels    < MAX_LABELS);
                    str_togo_using_label[numb_of_labels] = str_for_label_now;
                    label_for_str[str_for_label_now] = numb_of_labels;
                    label_used_in_str[position] = numb_of_labels;
                }
            else
            label_used_in_str[position] = label_for_str[str_for_label_now];
        }
        position++;
    }
    int other_label = 0,
          now_label = 0;
    for ( now_label = 1; now_label <= numb_of_labels; now_label++)
    {
        i = MAX_SIZE_OF_CODE;
        while ( i > str_togo_using_label[now_label])
        {
            assert( 0 < i < MAX_SIZE_OF_CODE);
            new_code[i] = new_code[i-1];
            i--;
        }
        new_code[str_togo_using_label[now_label]] = - now_label;
        length = 0;
        /*while (neof)
        {
            //printf( "new_code[%d] = %lf\n", length, new_code[length]);
            if ( new_code[length] == CMD_EF)
            neof = 0;
            length++;
        }
        /*i = 0;
        while ( i < 15)
        {
            //printf( "label_used_in_str[%d] = %d\n", i, label_used_in_str[i]);
            i++;
        }*/
        i = MAX_SIZE_OF_CODE;
        while ( i > str_togo_using_label[now_label])
        {
            assert( 0 < i < MAX_SIZE_OF_CODE);
            label_used_in_str[i] = label_used_in_str[i-1];
            i--;
        }
        /*while ( i < 15)
        {
            printf( "label_used_in_str[%d] = %d\n", i, label_used_in_str[i]);
            i++;
        }*/
        for ( other_label = 1; other_label <= numb_of_labels; other_label++)
        {
            if ( now_label != other_label && str_togo_using_label[other_label] > str_togo_using_label[now_label])
                str_togo_using_label[other_label]++;
        }
    }
    length = 0;
    /*while (neof)
        {
            //printf( "new_code[%d] = %lf\n", length, new_code[length]);
            if ( new_code[length] == CMD_EF)
            neof = 0;
            length++;
        }*/

    char  expected_end =  0;
    int     length_now =  0,
                   cmd =  0;
    numb_of_cmd = -1;
    neof = 1;
    position = 0;
    double value;
    while ( neof)
        {
            assert( 0 <= position < MAX_SIZE_OF_CODE);
            cmd = new_code[position];
            #include "CMD_CHECK.h"
            if (cmd < 0)
            {
                fprintf(out_file, ": %d", -cmd);
            }
            else
            {
                printf("This command doesn`t exist!!\n");
            }
            if ( cmd == CMD_push)
            {
                fprintf(out_file, " %0.2lf", new_code[++position]);
            }
            numb_of_cmd = cmd;
            if (numb_of_cmd == CMD_jmp   ||
                numb_of_cmd == CMD_je    ||
                numb_of_cmd == CMD_jne   ||
                numb_of_cmd == CMD_jbg   ||
                numb_of_cmd == CMD_jsml  ||
                numb_of_cmd == CMD_jnbg  ||
                numb_of_cmd == CMD_jnsml ||
                numb_of_cmd == CMD_call)
            {
                position++;
                assert( 0 <= position < MAX_SIZE_OF_CODE);
                fprintf(out_file, " :%d", label_used_in_str[position] );
            }
            fprintf(out_file, "\n");
            if ( cmd == CMD_EF)
                neof = 0;
            if ( cmd != CMD_EF && feof(in_code))
            {
                printf("Command 'EF' expected!\nWe will write it for you this time, but don`t forget it again!\n");
                assert( 0 <= position < MAX_SIZE_OF_CODE);
                new_code[position++] = CMD_EF;
                neof = 0;
            }
            position++;
        }
    }

